/**
 * 
 */
package denaris.core;

import java.util.Enumeration;
import java.util.Vector;

import javax.microedition.lcdui.Graphics;

import denaris.core.listener.IParticleListener;

/**
 * A particle emitter creates particles of any type. Emitters are responsible
 * for painting the particles they created (they could do this by forwarding the
 * paint-call they receive). They also implement a Particle cache which
 * optimizes object handling.
 * 
 * @author stkl23
 * 
 */
public abstract class AbstractParticleEmitter implements IParticleListener {
	/**
	 * the horizontal coordinate relative to the entity that creates the
	 * particle
	 */
	private int deltaX = 0;

	/** the vertical coordinate relative to the entity that creates the particle */
	private int deltaY = 0;

	/** the particle cache */
	private Vector cache;

	/** the maximum allowed number of particles */
	private int maxCacheSize;

	/**
	 * indicates if this emitter is active... this flag will not be tested by
	 * any of the methods of this class. That means an inactive emitter can
	 * still emitt particles if it's parent particle system tells it to. So it
	 * is the task of the Particle System to check the flag to see if it should
	 * involve this emitter.
	 */
	private boolean active = true;

	public AbstractParticleEmitter(int cacheSize, int dx, int dy) {
		cache = new Vector(cacheSize);
		deltaX = dx;
		deltaY = dy;
		maxCacheSize = cacheSize;
	}

	public void paint(Graphics g) {
		Enumeration e = cache.elements();
		while (e.hasMoreElements()) {
			AbstractParticle particle = (AbstractParticle) e.nextElement();
			if (particle.isActive()) {
				particle.paint(g);
			}
		}
	}

	protected AbstractParticle next() {
		AbstractParticle result = null;

		Enumeration e = cache.elements();
		while (e.hasMoreElements() && result == null) {
			AbstractParticle particle = (AbstractParticle) e.nextElement();
			if (!particle.isActive()) {
				result = particle;
			}
		}

		// still nothing there?
		if (result == null && cache.size() < maxCacheSize) {
			// yer, create a new particle
			result = createNew();
			// add it to the cache
			cache.addElement(result);
		}

		return result;
	}

	/**
	 * Emitts a new particle at the given position
	 * 
	 * @param x
	 * @param y
	 */
	public void emitt(int x, int y) {
		// we must emitt a new particle
		final AbstractParticle particle = next();
		// next() MAY have returned null in case the maximum size of the cache
		// was reached
		if (particle != null) {
			initializeEmittedParticle(x, y, particle);
		}
	}

	protected void initializeEmittedParticle(int x, int y, final AbstractParticle particle) {
		particle.getController().reset();
		particle.setPosition(x, y);
		particle.setParticleListener(this);
		particle.setActive(true);
	}

	public void particleIn(AbstractParticle particle) {
	}

	public void particleOut(AbstractParticle particle) {
		particle.setActive(false);
	}

	protected abstract AbstractParticle createNew();

	public int getDeltaX() {
		return deltaX;
	}

	public int getDeltaY() {
		return deltaY;
	}

	public int getMaxCacheSize() {
		return maxCacheSize;
	}

	public void setMaxCacheSize(int maxCacheSize) {
		this.maxCacheSize = maxCacheSize;
	}

	public void update() {
		Enumeration e = cache.elements();
		while (e.hasMoreElements()) {
			AbstractParticle particle = (AbstractParticle) e.nextElement();
			if (particle.isActive()) {
				particle.update();
			}
		}
	}

	public Enumeration elements() {
		return cache.elements();
	}

	public boolean isActive() {
		return active;
	}

	public void setActive(boolean active) {
		this.active = active;
	}
	
	public void reset() {
		// deactivate all particles
		Enumeration e = cache.elements();
		while (e.hasMoreElements()) {
			AbstractParticle particle = (AbstractParticle) e.nextElement();
			particle.setActive(false);
		}
	}
}
